package pl.donajski.magisterka;

import java.util.HashSet;

public class Task implements Comparable<Task> {
	
	/**
	 * @param index
	 * @param inputTransmissionRate
	 * @param outputTransmissionRate
	 * @param sourceNode
	 * @param isProtected
	 * @param primaryTask
	 * @param destinations
	 */
	public Task(int index, int inputTransmissionRate,
			int outputTransmissionRate, Node sourceNode,
			boolean isProtected, Task primaryTask, HashSet<Node> destinations,
			int projectIndex) {
		this.mIndex = index;
		this.mInputTransmissionRate = inputTransmissionRate;
		this.mOutputTransmissionRate = outputTransmissionRate;
		this.mSourceNode = sourceNode;
		this.mIsProtected = isProtected;
		this.mPrimaryTask = primaryTask;
		this.mDestinations = destinations;
		this.mProjectIndex = projectIndex;
	}
	
	@Override
	public String toString() {
		return 	this.mIndex + "\t" +
				( this.mAssignment == null ? "n/a" : this.mAssignment.getIndex() ) + "\t" +
				this.mInputTransmissionRate + "\t" +
				this.mOutputTransmissionRate + "\t" +
				this.mSourceNode + "\t" +
				this.mIsProtected + "\t" +
				this.isPrimary() + "\t" +
				this.mDestinations;
	}
	
	/**
	 * @return true if task is a primary task, false otherwise
	 */
	public boolean isPrimary() {
		return this.mPrimaryTask == null;
	}
	
	/**
	 * Gets task's unique index
	 * @return
	 */
	public int getIndex() {
		return mIndex;
	}
	/**
	 * Gets transmission rate of task r input data (Mbps). Paper notation a_r
	 * @return input transmission rate
	 */
	public int getInputTransmissionRate() {
		return mInputTransmissionRate;
	}
	/**
	 * Gets transmission rate of task r output data (Mbps). Paper notation b_r
	 * @return output transmission rate
	 */
	public int getOutputTransmissionRate() {
		return mOutputTransmissionRate;
	}
	/**
	 * Gets task's source node i. e. node that possesses task's input data before any transmissions.
	 * @return source node
	 */
	public Node getSourceNode() {
		return mSourceNode;
	}
	/**
	 * Gets task's protection indicator i. e. does task require protection
	 * @return true if task require protection, false otherwise
	 */
	public boolean isIsProtected() {
		return mIsProtected;
	}
	/**
	 * Gets task's primary index i. e. index of original task (primary task)
	 * @return primary task if task is backup task, null if task is primary task
	 */
	public Task getPrimaryIndex() {
		return mPrimaryTask;
	}
	/**
	 * Gets hashSet of nodes that are expecting to receive task output data
	 * @return nodes to send output data to
	 */
	public HashSet<Node> getDestinations() {
		return mDestinations;
	}
	/**
	 * Gets taks's assignment i. e. node responsible for executing this task
	 * @return assigned node
	 */
	public Node getAssignment() {
		return this.mAssignment;
	}
	public void setIndex(int index) {
		this.mIndex = index;
	}
	public void setInputTransmissionRate(int InputTransmissionRate) {
		this.mInputTransmissionRate = InputTransmissionRate;
	}
	public void setOutputTransmissionRate(int OutputTransmissionRate) {
		this.mOutputTransmissionRate = OutputTransmissionRate;
	}
	public void setSourceNode(Node sourceNode) {
		this.mSourceNode = sourceNode;
	}
	public void setIsProtected(boolean isProtected) {
		this.mIsProtected = isProtected;
	}
	public void setPrimaryIndex(Task primaryTask) {
		this.mPrimaryTask = primaryTask;
	}
	public void setDestinations(HashSet<Node> destinations) {
		this.mDestinations = destinations;
	}	
	/**
	 * @return the mProjectIndex
	 */
	public int getProjectIndex() {
		return mProjectIndex;
	}

	/**
	 * @param mProjectIndex the mProjectIndex to set
	 */
	public void setProjectIndex(int projectIndex) {
		this.mProjectIndex = projectIndex;
	}

	public void setAssignment(Node node) {
		if(this.mAssignment != null)
			this.mAssignment.removeAssignement();

		
		node.addAssignement();
		this.mAssignment = node;	
	}
	
	public void removeAssignment() {
		if(this.mAssignment != null)
			this.mAssignment.removeAssignement();
		this.mAssignment = null;
	}
	
	public int compareTo(Task o) {
		int flowOne = this.getOutputTransmissionRate();//this.getInputTransmissionRate() + this.getOutputTransmissionRate() * this.destinationSize();
		int flowTwo = o.getOutputTransmissionRate();//o.getInputTransmissionRate() + o.getOutputTransmissionRate() * o.destinationSize();
		
		if(flowOne > flowTwo)
			return -1;
		else if(flowOne < flowTwo)
			return 1;
		else
			return 0;
	}
	
	public boolean canAssign(Node n) {
		if(!n.canAssign())
			return false;
		
		if(this.getPrimaryIndex() != null && 
				this.getPrimaryIndex().getAssignment() != null && 
				this.getPrimaryIndex().getAssignment().equals(n))
			return false;
		
		if(this.getBackupTask() != null && 
				this.getBackupTask().getAssignment() != null && 
				this.getBackupTask().getAssignment().equals(n))
			return false;
		
		return true;
	}
	
	public boolean isValid() {
		if(this.getPrimaryIndex() != null && 
				this.getPrimaryIndex().getAssignment() != null && 
				this.getPrimaryIndex().getAssignment().equals(this.getAssignment()))
			return false;
		
		if(this.getBackupTask() != null && 
				this.getBackupTask().getAssignment() != null && 
				this.getBackupTask().getAssignment().equals(this.getAssignment()))
			return false;
		
		return true;
	}
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object arg0) {
		return mIndex == ((Task) arg0).getIndex();
	}
	

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return this.mIndex;
	}

	/**
	 * Checks whether task destinations contain specific node
	 * @param o Node to check
	 * @return true if node belong to destination nodes, false otherwise
	 */
	public boolean destinationContains(Object o) {
		return mDestinations.contains(o);
	}

	/**
	 * returns size of output destinations set
	 * @return size of output destinations set
	 */
	public int destinationSize() {
		return mDestinations.size();
	}
	
	public void setBackupTask(Task bckup) {
		this.mBackupTask = bckup;
		
	}
	
	public Task getBackupTask() {
		return this.mBackupTask;
	}



	private int mIndex;
	private int mInputTransmissionRate;
	private int mOutputTransmissionRate;
	private Node mSourceNode;
	private boolean mIsProtected;
	private Task mPrimaryTask;
	private HashSet<Node> mDestinations;
	private Node mAssignment;
	private int mProjectIndex;
	private Task mBackupTask;
	
}
